#ifndef AACDECODER_HPP
#define AACDECODER_HPP

#include "Decoder.hpp"
#include <neaacdec.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>

// declare buffering variables
/*#define DEC_BUFF_VARS \
    int fileread, bytesconsumed, k; \
    int buffercount = 0, buffer_index = 0; \
    unsigned char *buffer; \
    unsigned int bytes_in_buffer = 0;*/
// initialise buffering
#define INIT_BUFF(file) \
    fseek(file, 0, SEEK_END); \
    fileread = ftell(file); \
    fseek(file, 0, SEEK_SET); \
    buffer = (unsigned char*)malloc(FAAD_MIN_STREAMSIZE*MAX_CHANNELS); \
    memset(buffer, 0, FAAD_MIN_STREAMSIZE*MAX_CHANNELS); \
    bytes_in_buffer = fread(buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, file);
// skip bytes in buffer
#define UPDATE_BUFF_SKIP(bytes) \
    fseek(infile, bytes, SEEK_SET); \
    buffer_index += bytes; \
    buffercount = 0; \
    bytes_in_buffer = fread(buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, infile);

// update buffer
#define UPDATE_BUFF_READ \
    if (bytesconsumed > 0) { \
        for (k = 0; k < (FAAD_MIN_STREAMSIZE*MAX_CHANNELS - bytesconsumed); k++) \
            buffer[k] = buffer[k + bytesconsumed]; \
        bytes_in_buffer += fread(buffer + (FAAD_MIN_STREAMSIZE*MAX_CHANNELS) - bytesconsumed, 1, bytesconsumed, infile); \
        bytesconsumed = 0; \
    }

// update buffer indices after NeAACDecDecode
#define UPDATE_BUFF_IDX(frame) \
    bytesconsumed += frame.bytesconsumed; \
    buffer_index += frame.bytesconsumed; \
    bytes_in_buffer -= frame.bytesconsumed;

// true if decoding has to stop because of EOF
#define IS_FILE_END buffer_index >= fileread

// end buffering
#define END_BUFF if (buffer) free(buffer);

class AacDecoder : public Decoder {
    private:
        FILE *fh;
        NeAACDecHandle hDecoder;
        NeAACDecConfigurationPtr config;
        // declare buffering variables
        int fileread, bytesconsumed, k; \
        int buffercount, buffer_index; \
        unsigned char *buffer; \
        unsigned int bytes_in_buffer;
    public:
        bool load(const char* filename);
        void close();
        int decode(float *data, unsigned long frames, bool silence=false);
        bool seek(unsigned int frame);
        AacDecoder();
        ~AacDecoder();
};

#endif // AACDECODER_HPP
